//package org.lynn.db;
//
//import lombok.extern.slf4j.Slf4j;
//
//import java.io.Serializable;
//import java.net.NetworkInterface;
//import java.nio.BufferUnderflowException;
//import java.nio.ByteBuffer;
//import java.security.SecureRandom;
//import java.util.Date;
//import java.util.Enumeration;
//import java.util.concurrent.atomic.AtomicInteger;
//import java.util.concurrent.atomic.AtomicLong;
//
//import static org.springframework.util.Assert.notNull;
//
///**
// * @author gy
// * @date 2019/1/6 22:24
// */
//@Slf4j
//public final class ObjectId implements Comparable<ObjectId>, Serializable {
//    private static final long serialVersionUID = 3670079982654483072L;
//    private static final int LOW_ORDER_THREE_BYTES = 0x00ffffff;
//    /**
//     *机器信息
//     */
//    private static final int MACHINE_IDENTIFIER;
//    /**
//     * 进程信息
//     */
//    private static final short PROCESS_IDENTIFIER;
//    /**
//     * 线程安全的下一个随机数,每次生成自增+1
//     */
//    private static final AtomicLong NEXT_COUNTER = new AtomicLong(new SecureRandom().nextLong());
//    private static final char[] HEX_CHARS = new char[] {
//            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
//    static {
//        try {
//            MACHINE_IDENTIFIER = createMachineIdentifier();
//            PROCESS_IDENTIFIER = createProcessIdentifier();
//        } catch (Exception e) {
//            throw new RuntimeException(e);
//        }
//    }
//    private final int timestamp;
//    private final int machineIdentifier;
//    private final short processIdentifier;
//    private final int counter;
//    /**
//     * Create a new object id.
//     */
//    public ObjectId() {
//        this(new Date());
//    }
//    /**
//     * Constructs a new instance using the given date.
//     *
//     * @param date the date
//     */
//    public ObjectId(final Date date) {
//        this(dateToTimestampSeconds(date), MACHINE_IDENTIFIER, PROCESS_IDENTIFIER, NEXT_COUNTER.getAndIncrement(), false);
//    }
//    /**
//     * Constructs a new instances using the given date and counter.
//     *
//     * @param date the date
//     * @param counter the counter
//     * @throws IllegalArgumentException if the high order byte of counter is not zero
//     */
//    public ObjectId(final Date date, final int counter) {
//        this(date, MACHINE_IDENTIFIER, PROCESS_IDENTIFIER, counter);
//    }
//    /**
//     * Constructs a new instances using the given date, machine identifier, process identifier, and counter.
//     *
//     * @param date the date
//     * @param machineIdentifier the machine identifier
//     * @param processIdentifier the process identifier
//     * @param counter the counter
//     * @throws IllegalArgumentException if the high order byte of machineIdentifier or counter is not zero
//     */
//    public ObjectId(final Date date, final int machineIdentifier, final short processIdentifier, final int counter) {
//        this(dateToTimestampSeconds(date), machineIdentifier, processIdentifier, counter);
//    }
//    /**
//     * Creates an ObjectId using the given time, machine identifier, process identifier, and counter.
//     *
//     * @param timestamp the time in seconds
//     * @param machineIdentifier the machine identifier
//     * @param processIdentifier the process identifier
//     * @param counter the counter
//     * @throws IllegalArgumentException if the high order byte of machineIdentifier or counter is not zero
//     */
//    public ObjectId(final int timestamp, final int machineIdentifier, final short processIdentifier, final int counter) {
//        this(timestamp, machineIdentifier, processIdentifier, counter, true);
//    }
//    private ObjectId(
//            final int timestamp, final int machineIdentifier, final short processIdentifier, final int counter, final boolean checkCounter) {
//        if ((machineIdentifier & 0xff000000) != 0) {
//            throw new IllegalArgumentException("The machine identifier must be between 0 and 16777215 (it must fit in three bytes).");
//        }
//        if (checkCounter && ((counter & 0xff000000) != 0)) {
//            throw new IllegalArgumentException("The counter must be between 0 and 16777215 (it must fit in three bytes).");
//        }
//        this.timestamp = timestamp;
//        this.machineIdentifier = machineIdentifier;
//        this.processIdentifier = processIdentifier;
//        this.counter = counter & LOW_ORDER_THREE_BYTES;
//    }
//    /**
//     * Constructs a new instance from a 24-byte hexadecimal string representation.
//     *
//     * @param hexString the string to convert
//     * @throws IllegalArgumentException if the string is not a valid hex string representation of an ObjectId
//     */
//    public ObjectId(final String hexString) {
//        this(parseHexString(hexString));
//    }
//    /**
//     * Constructs a new instance from the given byte array
//     *
//     * @param bytes the byte array
//     * @throws IllegalArgumentException if array is null or not of length 12
//     */
//    public ObjectId(final byte[] bytes) {
//        this(ByteBuffer.wrap(notNull("bytes", bytes)));
//    }
//    /**
//     * Creates an ObjectId
//     *
//     * @param timestamp time in seconds
//     * @param machineAndProcessIdentifier machine and process identifier
//     * @param counter incremental value
//     */
//    ObjectId(final int timestamp, final int machineAndProcessIdentifier, final int counter) {
//        this(legacyToBytes(timestamp, machineAndProcessIdentifier, counter));
//    }
//    /**
//     * Constructs a new instance from the given ByteBuffer
//     *
//     * @param buffer the ByteBuffer
//     * @throws IllegalArgumentException if the buffer is null or does not have at least 12 bytes remaining
//     * @since 3.4
//     */
//    public ObjectId(final ByteBuffer buffer) {
//        notNull("buffer", buffer);
//        isTrueArgument("buffer.remaining() >=12", buffer.remaining() >= 12);
//// Note: Cannot use ByteBuffer.getInt because it depends on tbe buffer's byte order
//// and ObjectId's are always in big-endian order.
//        timestamp = makeInt(buffer.get(), buffer.get(), buffer.get(), buffer.get());
//        machineIdentifier = makeInt((byte) 0, buffer.get(), buffer.get(), buffer.get());
//        processIdentifier = (short) makeInt((byte) 0, (byte) 0, buffer.get(), buffer.get());
//        counter = makeInt((byte) 0, buffer.get(), buffer.get(), buffer.get());
//    }
//    /**
//     * Gets a new object id.
//     *
//     * @return the new id
//     */
//    public static ObjectId get() {
//        return new ObjectId();
//    }
//    /**
//     * Checks if a string could be an {@code ObjectId}.
//     *
//     * @param hexString a potential ObjectId as a String.
//     * @return whether the string could be an object id
//     * @throws IllegalArgumentException if hexString is null
//     */
//    public static boolean isValid(final String hexString) {
//        if (hexString == null) {
//            throw new IllegalArgumentException();
//        }
//        int len = hexString.length();
//        if (len != 24) {
//            return false;
//        }
//        for (int i = 0; i < len; i++) {
//            char c = hexString.charAt(i);
//            if (c >= '0' && c <= '9') {
//                continue;
//            }
//            if (c >= 'a' && c <= 'f') {
//                continue;
//            }
//            if (c >= 'A' && c <= 'F') {
//                continue;
//            }
//            return false;
//        }
//        return true;
//    }
//    /**
//     * Gets the generated machine identifier.
//     *
//     * @return an int representing the machine identifier
//     */
//    public static int getGeneratedMachineIdentifier() {
//        return MACHINE_IDENTIFIER;
//    }
//    /**
//     * Gets the generated process identifier.
//     *
//     * @return the process id
//     */
//    public static int getGeneratedProcessIdentifier() {
//        return PROCESS_IDENTIFIER;
//    }
//    /**
//     * Gets the current value of the auto-incrementing counter.
//     *
//     * @return the current counter value.
//     */
//    public static int getCurrentCounter() {
//        return NEXT_COUNTER.get();
//    }
//    /**
//     * <p>Creates an ObjectId using time, machine and inc values. The Java driver used to create all ObjectIds this way, but it does not
//     * match the <a href="http://docs.mongodb.org/manual/reference/object-id/">ObjectId specification</a>, which requires four values, not
//     * three. This major release of the Java driver conforms to the specification, but still supports clients that are relying on the
//     * behavior of the previous major release by providing this explicit factory method that takes three parameters instead of four.</p>
//     * <p>
//     * <p>Ordinary users of the driver will not need this method. It's only for those that have written there own BSON decoders.</p>
//     * <p>
//     * <p>NOTE: This will not break any application that use ObjectIds. The 12-byte representation will be round-trippable from old to new
//     * driver releases.</p>
//     *
//     * @param time time in seconds
//     * @param machine machine ID
//     * @param inc incremental value
//     * @return a new {@code ObjectId} created from the given values
//     * @since 2.12.0
//     */
//    public static ObjectId createFromLegacyFormat(final int time, final int machine, final int inc) {
//        return new ObjectId(time, machine, inc);
//    }
//    private static byte[] legacyToBytes(final int timestamp, final int machineAndProcessIdentifier, final int counter) {
//        byte[] bytes = new byte[12];
//        bytes[0] = int3(timestamp);
//        bytes[1] = int2(timestamp);
//        bytes[2] = int1(timestamp);
//        bytes[3] = int0(timestamp);
//        bytes[4] = int3(machineAndProcessIdentifier);
//        bytes[5] = int2(machineAndProcessIdentifier);
//        bytes[6] = int1(machineAndProcessIdentifier);
//        bytes[7] = int0(machineAndProcessIdentifier);
//        bytes[8] = int3(counter);
//        bytes[9] = int2(counter);
//        bytes[10] = int1(counter);
//        bytes[11] = int0(counter);
//        return bytes;
//    }
//    private static int createMachineIdentifier() {
//// build a 2-byte machine piece based on NICs info
//        int machinePiece;//机器码
//        try {
//            StringBuilder sb = new StringBuilder();
//            Enumeration<NetworkInterface> e = NetworkInterface.getNetworkInterfaces();// 返回机器所有的网络接口，包含物理ip和虚拟ip
//            while (e.hasMoreElements()) {//遍历网络接口
//                NetworkInterface ni = e.nextElement();// 网络接口信息
//                sb.append(ni.toString());
//                byte[] mac = ni.getHardwareAddress();//获取机器mac地址
//                if (mac != null) {
//                    ByteBuffer bb = ByteBuffer.wrap(mac);
//                    try {
//                        sb.append(bb.getChar());
//                        sb.append(bb.getChar());
//                        sb.append(bb.getChar());
//                    } catch (BufferUnderflowException shortHardwareAddressException) { //NOPMD
//// mac with less than 6 bytes. continue
//                    }
//                }
//            }
//            machinePiece = sb.toString().hashCode();//最后将机器信息字符串的hashcode作为机器码返回
//        } catch (Throwable t) {
//// exception sometimes happens with IBM JVM, use random
//            machinePiece = (new SecureRandom().nextInt());//如果异常则使用随机数当作机器码
//            log.warn("Failed to get machine identifier from network interface, using random number instead", t);
//        }
//        machinePiece = machinePiece & LOW_ORDER_THREE_BYTES;//将机器码与固定数做一边与操作
//        return machinePiece;
//    }
//    // Creates the process identifier. This does not have to be unique per class loader because
//// NEXT_COUNTER will provide the uniqueness.
//    private static short createProcessIdentifier() {
//        short processId;
//        try {
//            String processName = java.lang.management.ManagementFactory.getRuntimeMXBean().getName();
//            if (processName.contains("@")) {
//                processId = (short) Integer.parseInt(processName.substring(0, processName.indexOf('@')));
//            } else {
//                processId = (short) java.lang.management.ManagementFactory.getRuntimeMXBean().getName().hashCode();
//            }
//        } catch (Throwable t) {
//            processId = (short) new SecureRandom().nextInt();
//            log.warn("Failed to get process identifier from JMX, using random number instead", t);
//        }
//        return processId;
//    }
//    private static byte[] parseHexString(final String s) {
//        if (!isValid(s)) {
//            throw new IllegalArgumentException("invalid hexadecimal representation of an ObjectId: [" + s + "]");
//        }
//        byte[] b = new byte[12];
//        for (int i = 0; i < b.length; i++) {
//            b[i] = (byte) Integer.parseInt(s.substring(i * 2, i * 2 + 2), 16);
//        }
//        return b;
//    }
//    private static int dateToTimestampSeconds(final Date time) {
//        return (int) (time.getTime() / 1000);
//    }
//    private static int makeInt(final byte b3, final byte b2, final byte b1, final byte b0) {
//// CHECKSTYLE:OFF
//        return (((b3) << 24) | ((b2 & 0xff) << 16) | ((b1 & 0xff) << 8) | ((b0 & 0xff)));
//// CHECKSTYLE:ON
//    }
//    private static byte int3(final int x) {
//        return (byte) (x >> 24);
//    }
//    private static byte int2(final int x) {
//        return (byte) (x >> 16);
//    }
//    private static byte int1(final int x) {
//        return (byte) (x >> 8);
//    }
//    private static byte int0(final int x) {
//        return (byte) (x);
//    }
//    private static byte short1(final short x) {
//        return (byte) (x >> 8);
//    }
//    private static byte short0(final short x) {
//        return (byte) (x);
//    }
//// Deprecated methods
//    /**
//     * Convert to a byte array. Note that the numbers are stored in big-endian order.
//     *
//     * @return the byte array
//     */
//    public byte[] toByteArray() {
//        ByteBuffer buffer = ByteBuffer.allocate(12);
//        putToByteBuffer(buffer);
//        return buffer.array(); // using .allocate ensures there is a backing array that can be returned
//    }
//    /**
//     * Convert to bytes and put those bytes to the provided ByteBuffer.
//     * Note that the numbers are stored in big-endian order.
//     *
//     * @param buffer the ByteBuffer
//     * @throws IllegalArgumentException if the buffer is null or does not have at least 12 bytes remaining
//     * @since 3.4
//     */
//    public void putToByteBuffer(final ByteBuffer buffer) {
//        notNull("buffer", buffer);
//        isTrueArgument("buffer.remaining() >=12", buffer.remaining() >= 12);
//        buffer.put(int3(timestamp));
//        buffer.put(int2(timestamp));
//        buffer.put(int1(timestamp));
//        buffer.put(int0(timestamp));
//        buffer.put(int2(machineIdentifier));
//        buffer.put(int1(machineIdentifier));
//        buffer.put(int0(machineIdentifier));
//        buffer.put(short1(processIdentifier));
//        buffer.put(short0(processIdentifier));
//        buffer.put(int2(counter));
//        buffer.put(int1(counter));
//        buffer.put(int0(counter));
//    }
//    /**
//     * Gets the timestamp (number of seconds since the Unix epoch).
//     *
//     * @return the timestamp
//     */
//    public int getTimestamp() {
//        return timestamp;
//    }
//    /**
//     * Gets the machine identifier.
//     *
//     * @return the machine identifier
//     */
//    public int getMachineIdentifier() {
//        return machineIdentifier;
//    }
//    /**
//     * Gets the process identifier.
//     *
//     * @return the process identifier
//     */
//    public short getProcessIdentifier() {
//        return processIdentifier;
//    }
//    /**
//     * Gets the counter.
//     *
//     * @return the counter
//     */
//    public int getCounter() {
//        return counter;
//    }
//    /**
//     * Gets the timestamp as a {@code Date} instance.
//     *
//     * @return the Date
//     */
//    public Date getDate() {
//        return new Date(timestamp * 1000L);
//    }
//    /**
//     * Converts this instance into a 24-byte hexadecimal string representation.
//     *
//     * @return a string representation of the ObjectId in hexadecimal format
//     */
//    public String toHexString() {
//        char[] chars = new char[24];
//        int i = 0;
//        for (byte b : toByteArray()) {
//            chars[i++] = HEX_CHARS[b >> 4 & 0xF];
//            chars[i++] = HEX_CHARS[b & 0xF];
//        }
//        return new String(chars);
//    }
//    // Big-Endian helpers, in this class because all other BSON numbers are little-endian
//    @Override
//    public int hashCode() {
//        int result = timestamp;
//        result = 31 * result + machineIdentifier;
//        result = 31 * result + (int) processIdentifier;
//        result = 31 * result + counter;
//        return result;
//    }
//    @Override
//    public boolean equals(final Object o) {
//        if (this == o) {
//            return true;
//        }
//        if (o == null || getClass() != o.getClass()) {
//            return false;
//        }
//        ObjectId objectId = (ObjectId) o;
//        if (counter != objectId.counter) {
//            return false;
//        }
//        if (machineIdentifier != objectId.machineIdentifier) {
//            return false;
//        }
//        if (processIdentifier != objectId.processIdentifier) {
//            return false;
//        }
//        if (timestamp != objectId.timestamp) {
//            return false;
//        }
//        return true;
//    }
//    @Override
//    public String toString() {
//        return toHexString();
//    }
//    @Override
//    public int compareTo(final ObjectId other) {
//        if (other == null) {
//            throw new NullPointerException();
//        }
//        byte[] byteArray = toByteArray();
//        byte[] otherByteArray = other.toByteArray();
//        for (int i = 0; i < 12; i++) {
//            if (byteArray[i] != otherByteArray[i]) {
//                return ((byteArray[i] & 0xff) < (otherByteArray[i] & 0xff)) ? -1 : 1;
//            }
//        }
//        return 0;
//    }
//    /**
//     * Gets the time of this ID, in seconds.
//     *
//     * @return the time component of this ID in seconds
//     * @deprecated Use #getTimestamp instead
//     */
//    @Deprecated
//    public int getTimeSecond() {
//        return timestamp;
//    }
//    /**
//     * Gets the time of this instance, in milliseconds.
//     *
//     * @return the time component of this ID in milliseconds
//     * @deprecated Use #getDate instead
//     */
//    @Deprecated
//    public long getTime() {
//        return timestamp * 1000L;
//    }
//    /**
//     * @return a string representation of the ObjectId in hexadecimal format
//     * @see ObjectId#toHexString()
//     * @deprecated use {@link #toHexString()}
//     */
//    @Deprecated
//    public String toStringMongod() {
//        return toHexString();
//    }
//}